package com.muchenxinxi.androidbaseapp.utils;

import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.support.v7.app.AlertDialog;

/**
 * ┏--------------------
 * │        /) /)
 * │     ฅ(• ﻌ •)ฅ
 * │  Created by HaoKing on 2017/2/23.
 * │  www.muchenxinxi.com
 * │  www.nextdever.com
 * │  QQ:773693552
 * │  QQ群: Geek Chat 344386592
 * ┗--------------------
 */

/**
 * 在Application中初始化即可
 * CrashCatcher.getInstance().init(mContext);
 * CrashCatcher.getInstance().init(mContext).setOnCrashCatchListener(this);
 */
public class CrashCatcher implements Thread.UncaughtExceptionHandler {

    //定义一个CallBack用来自定义处理Crash事件
    public interface OnCrashCatchListener {
        boolean onCrashCatch(Throwable ex, String crashReportText);
    }

    // 程序的Context对象
    private Context mContext;
    // CrashHandler实例
    private static CrashCatcher INSTANCE;
    // 系统默认的UncaughtException处理类
    private Thread.UncaughtExceptionHandler mDefaultHandler;
    private OnCrashCatchListener mOnCrashCatchListener;

    //保证只有一个CrashCatchUtils实例
    private CrashCatcher() {
    }

    //获取CrashHandler实例 ,单例模式
    public static CrashCatcher getInstance() {
        if (INSTANCE == null)
            INSTANCE = new CrashCatcher();
        return INSTANCE;
    }

    /**
     * 初始化
     *
     * @param context
     */
    public CrashCatcher init(Context context) {
        mContext = context;
        // 获取系统默认的UncaughtException处理器
        mDefaultHandler = Thread.getDefaultUncaughtExceptionHandler();
        // 设置该CrashHandler为程序的默认处理器
        Thread.setDefaultUncaughtExceptionHandler(this);
        return INSTANCE;
    }

    public void setOnCrashCatchListener(OnCrashCatchListener onCrashCatchListener) {
        this.mOnCrashCatchListener = onCrashCatchListener;
    }

    /**
     * 当UncaughtException发生时会转入该重写的方法来处理
     */
    public void uncaughtException(Thread thread, Throwable ex) {
        if (!handleException(ex) && mDefaultHandler != null) {
            // 如果自定义的没有处理或没有处理完则让系统默认的异常处理器来处理
            mDefaultHandler.uncaughtException(thread, ex);
        }
    }

    /**
     * 自定义错误处理,收集错误信息 发送错误报告等操作均在此完成.
     *
     * @param ex 异常信息
     * @return true 表示正常处理了该异常信息，否则返回false.
     */
    public boolean handleException(Throwable ex) {
        if (ex == null || mContext == null)
            return false;
        final String crashReportText = getCrashReport(mContext, ex);
        //如果没有自定义处理方法，则打印错误，并重启应用
        if (null == mOnCrashCatchListener) {
            ex.printStackTrace();
            Intent intent = mContext.getPackageManager().getLaunchIntentForPackage(mContext.getPackageName());
            intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
            mContext.startActivity(intent);
            android.os.Process.killProcess(android.os.Process.myPid());
            return true;
        } else {
            return mOnCrashCatchListener.onCrashCatch(ex, crashReportText);
        }
    }

    /**
     * 获取APP崩溃异常报告
     *
     * @param ex
     * @return
     */
    private String getCrashReport(Context context, Throwable ex) {
        PackageInfo pinfo = getPackageInfo(context);
        StringBuffer exceptionStr = new StringBuffer();
        exceptionStr.append("Version: " + pinfo.versionName + "(" + pinfo.versionCode + ")\n");
        exceptionStr.append("Android: " + android.os.Build.VERSION.RELEASE + "(" + android.os.Build.MODEL + ")\n");
        exceptionStr.append("Exception: " + ex.getMessage() + "\n");
        StackTraceElement[] elements = ex.getStackTrace();
        for (int i = 0; i < elements.length; i++) {
            exceptionStr.append(elements[i].toString() + "\n");
        }
        return exceptionStr.toString();
    }

    /**
     * 获取App安装包信息
     *
     * @return
     */
    private PackageInfo getPackageInfo(Context context) {
        PackageInfo info = null;
        try {
            info = context.getPackageManager().getPackageInfo(
                    context.getPackageName(), 0);
        } catch (PackageManager.NameNotFoundException e) {
            e.printStackTrace(System.err);
        }
        if (info == null)
            info = new PackageInfo();
        return info;
    }
}
